在觀察電池最佳化設定的問題是否被排除的同時,讓我們來解決通知重複的 bug 吧!
筆者調查了官方文件,發現我們當初透過 createTriggerNotification
建立任務時,並沒有提供 id。
此外,如果有 id 已經通知排程了,則 createTriggerNotification
的效果會是 update
既有的 id,可以說這個 API 其實是 upsert
的行為。
若我們不提供 id,根據官方的文件是隨機 gen 出來的:
Defaults to a random string if not provided.
筆者亦發現有取得目前所有建立的通知任務 id
的 API: getTriggerNotificationIds
。
讓我們在 notification.js 中的 setNotificationByWeekDay
加入這段驗證一下:
const ids = await notifee.getTriggerNotificationIds();
console.log(ids.length);
要記得把 fuction 改成 async。
refresh app 幾次,印出來後我們可以看到:
14
筆的幅度在增長,符合我們先前的推斷理由是, setNotificationByWeekDay
會在一週七天,分別建立早上以及晚上的通知:
for (const predict of nightPrediction) {
const {weekday, time} = predict;
// night notification
onCreateTriggerNotificationByWeekday(time, weekday);
// morning notification
onCreateTriggerNotificationByWeekday(dayPredcition, weekday);
}
所以每次 app 刷新時, useEffect
內的 setNotificationByWeekDay
都會在既有的任務 list 中加入 14 筆通知排程。
筆者決定加入通知 id,來讓每次 app 刷新只是 update 既有的任務,而非 create 新的任務。
筆者希望簡單就好,快速決定是 $weekday-$nightorday
的格式。
首先我們在 onCreateTriggerNotificationByWeekday
中加入第三個參數 isNight
,以及以下邏輯:
const customizedNotificationId =
isNight === undefined
? null
: isNight
? `${weekday}-night`
: `${weekday}-day`;
onCreateTriggerNotification(
absoluteTimeInMs,
message,
customizedNotificationId,
);
例如以週二早上
為例,我們 weekday
傳入的值是 tue
,isNight
傳入的是 false
,就會組出 tue-day
。同時也保有如果沒有傳入 isNight 時,就委由底層邏輯幫忙產出 id 的彈性。
我們將自製的 id 傳入真正 call notifee api 的 onCreateTriggerNotification
中。同時,我們在 setNotificationByWeekDay
加入第三個參數:
for (const predict of nightPrediction) {
const {weekday, time} = predict;
// night notification
onCreateTriggerNotificationByWeekday(time, weekday, true);
// morning notification
onCreateTriggerNotificationByWeekday(dayPredcition, weekday, false);
}
進一步,同時筆者也實作了上層 function 沒有提供 id 時的備案,然而途中碰到一些問題,記錄如下:
筆者首先嘗試的是 uuid,
id: id || uuidv4(),
但得到以下錯誤訊息:
crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported
找到了這篇討論:https://github.com/uuidjs/uuid/issues/416
快速瀏覽過去,心中有已想好備案,問題看似無法馬上排除,所以決定不用 uuid 套件。
使用時,碰到以下問題:
ReferenceError: Property 'crypto' doesn't exist
怎麼都是 crypto
相關的,筆者決定有空再來調查亂數產生的 id。
由於目前沒有其他需求,只是要做到通知任務不重複
以及管理通知而已,故筆者的 workaround 為使用 Date
的 ISOString
:
id: id || new Date().toISOString(),
最終底層的 id 就會是客製化後傳入的,不然就是直接使用 Date ISOString 來作為 ID。
export async function onCreateTriggerNotification(
time: String,
message: String,
id: String | null,
) {
...
// Create a trigger notification
await notifee.createTriggerNotification(
{
id: id || new Date().toISOString(),
title: '關門通知',
body: message || '樓下關門即將在 10 分鐘內發生',
android: {
channelId,
pressAction: {
id: 'default',
},
},
},
trigger,
);
}
幾次刷新後,任務數目仍然維持一樣的,可以看到 notifee 幫忙產生的 id、實作過程中以日期產生的 id 以及我們客製的 id 同時共存。
bug 解決!
筆者先前沒發現文件有提及循環通知
。
我們可以在 trigger
加入循環通知週期
(repeatFrequency
):
const trigger: TimestampTrigger = {
type: TriggerType.TIMESTAMP,
timestamp: time,
repeatFrequency: RepeatFrequency.WEEKLY,
};
筆者決定以此實作,並刪除原先 useEffect 中設定循環通知的段落:
// trigger every 7 days
setInterval(setNotificationByWeekDay, sevenDaysInterval);
初步看下來這個 bug 算是解決了,而且還優化了循環通知邏輯,讓我們使用幾天驗證一下吧!
今天收工!